package com.azh.server.server;

import com.azh.server.parser.Aarser;
import com.azh.server.parser.statement.Abort;
import com.azh.server.parser.statement.Begin;
import com.azh.server.parser.statement.Commit;
import com.azh.server.parser.statement.Create;
import com.azh.server.parser.statement.Delete;
import com.azh.server.parser.statement.Insert;
import com.azh.server.parser.statement.Select;
import com.azh.server.parser.statement.Show;
import com.azh.server.parser.statement.Update;
import com.azh.server.tables.BeginRes;
import com.azh.server.tables.TableManager;

/**
 * @author zhaozhenhang <zhaozhenhang@kuaishou.com>
 * Created on 2022-05-02
 * 调用Parser获取对应语句的结构化信息对象，并根据对象类型，调用tbm不同方法进行处理
 */
public class Executor {

    private long txId;

    public TableManager tableManager;

    public Executor(TableManager tableManager) {
        this.tableManager = tableManager;
        this.txId = 0;
    }

    public void close() {
        if (txId != 0) {
            tableManager.abort(txId);
        }
    }

    public byte[] execute(byte[] sql) throws Exception {
        Object stat = Aarser.parse(sql);
        if(Begin.class.isInstance(stat)) {
            if(txId != 0) {
                throw new RuntimeException("Nested transaction not supported!");
            }

            BeginRes r = tableManager.begin((Begin)stat);
            txId = r.txId;
            return r.result;
        } else if(Commit.class.isInstance(stat)) {
            if(txId == 0) {
                throw new RuntimeException("Nested transaction not supported!");
            }
            byte[] res = tableManager.commit(txId);
            txId = 0;
            return res;
        } else if(Abort.class.isInstance(stat)) {
            if(txId == 0) {
                throw new RuntimeException("Nested transaction not supported!");
            }
            byte[] res = tableManager.abort(txId);
            txId = 0;
            return res;
        } else {
            return execute2(stat);
        }
    }

    private byte[] execute2(Object stat) throws Exception {
        boolean tmpTransaction = false;
        Exception e = null;
        if(txId == 0) {
            tmpTransaction = true;
            BeginRes r = tableManager.begin(new Begin());
            txId = r.txId;
        }
        try {
            byte[] res = null;
            if(Show.class.isInstance(stat)) {
                res = tableManager.show(txId);
            } else if(Create.class.isInstance(stat)) {
                res = tableManager.create(txId, (Create)stat);
            } else if(Select.class.isInstance(stat)) {
                res = tableManager.read(txId, (Select)stat);
            } else if(Insert.class.isInstance(stat)) {
                res = tableManager.insert(txId, (Insert)stat);
            } else if(Delete.class.isInstance(stat)) {
                res = tableManager.delete(txId, (Delete)stat);
            } else if(Update.class.isInstance(stat)) {
                res = tableManager.update(txId, (Update)stat);
            }
            return res;
        } catch(Exception e1) {
            e = e1;
            throw e;
        } finally {
            if(tmpTransaction) {
                if(e != null) {
                    System.out.println("e: "+e.getMessage());
                    tableManager.abort(txId);
                } else {
                    tableManager.commit(txId);
                }
                txId = 0;
            }
        }
    }
}
